package com.pf.business.upload.controller;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.read.listener.PageReadListener;
import com.google.common.collect.Lists;
import com.pf.business.upload.dto.UploadBill;
import com.pf.business.upload.listener.AsyncUploadBillReadListener;
import com.pf.business.upload.listener.UploadBillReadListener;
import com.pf.common.dto.ExcelErrorParam;
import com.pf.common.dto.ResultResp;
import com.pf.utils.ResultRespUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.util.List;

/**
 * @author PanFei
 * @version 1.0.0
 * @createTime 2023/7/16 16:08
 */
@RestController
@RequestMapping("/excel")
public class UploadController {

    @Autowired
    @Qualifier("asyncLogExecutor")
    private ThreadPoolTaskExecutor taskExecutor;

    /**
     * 上传校验账单数据
     *
     * @param file      账单excel文件
     * @param isBlocked true-数据校验异常，立即返回；否则跳过校验不通过数据，继续校验下一行数据
     * @return
     * @throws Exception
     */
    @PostMapping("/uploadBill")
    public ResultResp uploadBill(@RequestParam("file") MultipartFile file,
                                 @RequestParam(value = "isBlocked", defaultValue = "true") Boolean isBlocked) throws Exception {
        List<UploadBill> billList = Lists.newArrayList();
        EasyExcel.read(file.getInputStream(), UploadBill.class, new UploadBillReadListener(billList, isBlocked))
                .sheet()
                .doRead();

        // 打印需存储的数据
        System.out.println(">>>>> 打印需存储的数据...");
        billList.forEach(System.out::println);
        return ResultRespUtils.success();
    }

    @PostMapping("/pageUploadBill")
    public ResultResp pageUploadBill(@RequestParam("file") MultipartFile file) throws Exception {

        // PageReadListener是easyExcel自带的监听器，可以分批处理数据，本案例没两条数据处理一次
        PageReadListener.BATCH_COUNT = 2;
        EasyExcel.read(file.getInputStream(), UploadBill.class, new PageReadListener<UploadBill>(billList -> {
            billList.forEach(System.out::println);
        })).sheet().doRead();

        return ResultRespUtils.success();
    }

    /**
     * 参考博客：
     * CompletionService的使用：  https://blog.csdn.net/Smy_0114/article/details/126094380
     * CompletionService的使用：  https://blog.csdn.net/qq_40276626/article/details/119961854
     * <p>
     * CompletableFuture的使用：  https://blog.csdn.net/qq_43803129/article/details/126609353
     * <p>
     * 异步处理上传文件，不适用于先校验所有数据，再处理校验通过的数据；只适用于边校验数据，边处理校验通过的数据。最后将所有校验不通过的数据原因一起返回
     *
     * @param file
     * @return
     * @throws Exception
     */
    @PostMapping("/asyncUploadBill")
    public ResultResp asyncUploadBill(@RequestParam("file") MultipartFile file) throws Exception {
        long startTime = System.currentTimeMillis();
        List<ExcelErrorParam> excelErrorMsgList = Lists.newArrayList();
        AsyncUploadBillReadListener.BATCH_COUNT = 2;
        EasyExcel.read(file.getInputStream(), UploadBill.class, new AsyncUploadBillReadListener(billList -> {
//            processBillData(billList);
            taskExecutor.execute(() -> {
                processBillData(billList);
            });
        }, excelErrorMsgList)).sheet().doRead();
        System.out.println("异常信息；" + excelErrorMsgList);
        long endTime = System.currentTimeMillis();
        System.out.println("耗时：" + (endTime - startTime) + "ms");
        return ResultRespUtils.success(excelErrorMsgList);
    }

    /**
     * 模拟处理账单数据
     *
     * @param billList
     */
    private void processBillData(List<UploadBill> billList) {
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        billList.forEach(System.out::println);
    }
}
